﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using SuppKids.Core.Domain;
using SuppKids.Core.Exceptions;
using SuppKids.Core.Repository;

namespace SuppKids.Core.Services
{
    public class BaseService<T> : IService where T : Entity
	{
		protected BaseService(IRepository<T> repository)
		{
			this.Repository = repository;
		}

		protected virtual IRepository<T> Repository { get; set; }

		public virtual T GetOneByIdOrDefault(int id, params Expression<Func<T, object>>[] includes)
		{
			return this.Repository.SingleOrDefault(a => a.Id == id, includes);
		}

		public virtual T GetOneById(int id, params Expression<Func<T, object>>[] includes)
		{
			var result = this.GetOneByIdOrDefault(id, includes);
			if (result == null)
			{
				throw new EntityNotFoundException(typeof(T), id);
			}

			return result;
		}

		public virtual IQueryable<T> GetQuery()
		{
			return this.Repository.GetQuery();
		}

        public virtual IEnumerable<T> GetAll(Expression<Func<T, bool>> whereCondition, params Expression<Func<T, object>>[] includes)
        {
            return this.Repository.GetAll(whereCondition, includes);
        }

		public virtual IEnumerable<T> GetAll(params Expression<Func<T, object>>[] includes)
		{
			return this.Repository.GetAll(includes);
		}

		public virtual IEnumerable<T> GetPage<TKey>(int pageNumber, int pageSize, out int totalCount, Expression<Func<T, bool>> whereCondition, Expression<Func<T, TKey>> orderBy, bool orderByAscending = true, params Expression<Func<T, object>>[] includes)
		{
			return this.Repository.GetPage(pageNumber, pageSize, out totalCount, whereCondition, orderBy, orderByAscending, includes);
		}

		public virtual IEnumerable<T> GetPage<TKey>(int pageNumber, int pageSize, out int totalCount, Expression<Func<T, bool>> whereCondition, Func<IQueryable<T>, IQueryable<T>> orderByClause = null, params Expression<Func<T, object>>[] includes)
		{
			return this.Repository.GetPage<TKey>(pageNumber, pageSize, out totalCount, whereCondition, orderByClause, includes);
		}

		public virtual IEnumerable<T> GetPageOrderedById(int pageNumber, int pageSize, out int totalCount)
		{
			return this.Repository.GetPageOrderedById(pageNumber, pageSize, out totalCount);
		}

		public virtual void RegisterDelete(T entity, bool flush = false)
		{
			if (entity != null)
			{               
				this.Repository.Delete(entity);
				if (flush)
				{
					this.Repository.SaveChanges();
				}
			}
		}
       
		public virtual T RegisterSave(T entity, bool saveChanges = false)
		{
		    if (entity.IsTransient)
		    {
		        this.Repository.Add(entity);
		    }

			if (saveChanges)
			{
				this.SaveChanges();
			}

			return entity;
		}

		public virtual void SaveChanges()
		{
			this.Repository.SaveChanges();
		}
	}
}